/**
 * @version 2007-1-6
 * @author xalinx at gmail dot com
 */
package org.nanhill.webflow.spring;

import java.lang.reflect.Method;

import org.nanhill.commons.pattern.flow.Action;
import org.nanhill.commons.pattern.flow.ActionContext;
import org.nanhill.commons.pattern.flow.ActionException;
import org.nanhill.commons.pattern.flow.ActionFactory;
import org.nanhill.commons.pattern.flow.DefaultAction;
import org.nanhill.commons.pattern.flow.DefaultEventFactory;
import org.nanhill.commons.pattern.flow.DefaultFlowConfig;
import org.nanhill.commons.pattern.flow.DefaultStateFactory;
import org.nanhill.commons.pattern.flow.EventFactory;
import org.nanhill.commons.pattern.flow.FlowConfig;
import org.nanhill.commons.pattern.flow.FlowFactory;
import org.nanhill.commons.pattern.flow.StateFactory;
import org.springframework.core.io.Resource;

/**
 * @version 2007-1-6
 * @author xalinx at gmail dot com
 * 
 */
public class XmlFlowFactoryBean extends AbstractFlowFactoryBean {

	private Resource[] flowLocations;

	private ActionFactory actionFactory = new BeanActionFactory(this);

	private EventFactory eventFactory = new DefaultEventFactory();

	private StateFactory stateFactory = new DefaultStateFactory();

	public void setFlowLocations(Resource[] flowLocations) {
		this.flowLocations = flowLocations;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.nanhill.webflow.spring.AbstractFlowFactoryBean#buildFlowFactory()
	 */
	@Override
	protected FlowFactory buildFlowFactory() throws Exception {
		FlowConfig config = new DefaultFlowConfig();
		if (this.flowLocations != null) {
			for (int i = 0; i < this.flowLocations.length; i++) {
				Resource resource = this.flowLocations[i];
				config.addFlowLocation(resource.getFile().getAbsolutePath());
			}
		}
		config.setActionFactory(actionFactory);
		config.setEventFactory(eventFactory);
		config.setStateFactory(stateFactory);
		FlowFactory flowFactory = config.buildFlowFactory();
		return flowFactory;
	}

	private final static class BeanActionFactory implements ActionFactory {
		private AbstractFlowFactoryBean flowFactoryBean;

		public BeanActionFactory(AbstractFlowFactoryBean flowFactoryBean) {
			this.flowFactoryBean = flowFactoryBean;
		}

		public Action createAction(String id, String methodName)
				throws ActionException {
			Object target = this.flowFactoryBean.getActionTarget(id);
			Method method;
			try {
				method = target.getClass().getMethod(methodName,
						new Class[] { ActionContext.class });
			} catch (Exception e) {
				String errmsg = "no method:" + methodName
						+ " in action target:" + target;
				throw new ActionException(errmsg, e);
			}
			return new DefaultAction(id, target, method);
		}
	}

}
